﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace UniUI.ConsoleUI
{
    public static class ConsoleUIManager
    {
        private static Task<ConsoleKeyInfo> getKeyTask;

        static ConsoleUIManager()
        {
            Screen = new ConsoleScreen();
            getKeyTask = new Task<ConsoleKeyInfo>(() => Console.ReadKey(true));
            InputEnabled = true;
        }

        public static ConsoleScreen Screen
        {
            get;
            private set;
        }

        public static bool InputEnabled { get; set; }

        private static ConsoleWindow _Window;
        public static ConsoleWindow Window
        {
            get { return _Window; }
            set
            {
                value.MainControl.Invalidate();
                _Window = value;
                Refresh();
            }
        }

        private static volatile bool stopped;
        private static volatile bool isRunning;

        public static void Start()
        {
            stopped = false;
            var theThread = new Thread(delegate()
            {
                bool isInsertMode = true;
                int cursorSize = Console.CursorSize;
                Console.CursorSize = 10;

                //render before listening keyboard
                Refresh();

                isRunning = true;
                Console.TreatControlCAsInput = true;

                try
                {
                    while (!stopped)
                    {
                        var kk = Console.ReadKey(true);
                        if (kk.Key == ConsoleKey.Insert)
                        {
                            isInsertMode = !isInsertMode;
                            Console.CursorSize = isInsertMode ? 10 : 100;
                            continue;
                        }
                        if (!InputEnabled)
                        {
                            continue;
                        }
                        var theWindow = Window;
                        if (theWindow != null)
                        {
                            theWindow.MainControl.OnKeyPress(kk, isInsertMode);
                        }

                        //render
                        Refresh();
                    }
                }
                finally
                {
                    isRunning = false;
                    Console.CursorSize = cursorSize;
                    Console.TreatControlCAsInput = false;
                }
            });
            theThread.Start();
        }

        private static object refreshLockObject = new object();

        public static void Refresh()
        {
            lock (refreshLockObject)
            {
                var theWindow = Window;
                if (theWindow != null)
                {
                    theWindow.MainControl.Render(Screen);
                }
                else
                {
                    Screen.BackgroundColor = ConsoleColor.Black;
                    Screen.Clear();
                }

                Screen.Present();
            }
        }

        public static void Stop()
        {
            stopped = true;
        }

        public static bool IsRunning
        {
            get { return isRunning; }
        }

        //should be carefully used (not in rendering, refresh after use if not in event handling)
        public static void Invalidate(int left, int top, int width, int height)
        {
            //TODO after supporting multiple window, we should iterate all windows
            var theWindow = Window;
            if (theWindow != null)
            {
                theWindow.Invalidate(left, top, width, height);
            }
        }
    }
}
